package com.billow.net
{
	import com.billow.encode.AES;
	import com.billow.events.ClientEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Timer;
	
	[Event(name="connectSucceed", type="com.billow.events.ClientEvent")]
	[Event(name="connectFailed", type="com.billow.events.ClientEvent")]
	[Event(name="progress", type="com.billow.events.ClientEvent")]
	[Event(name="receive", type="com.billow.events.ClientEvent")]
	[Event(name="ioError", type="com.billow.events.ClientEvent")]
	
	public class Client extends EventDispatcher
	{
		private var _key:String;
		private var _timer:Timer;
		private var _socket:Socket;
		private var _serverAddress:String;
		private var _serverPort:int;
		private var _isHeader:Boolean;
		private var _close:Boolean;
		
		/**
		 * 
		 * @param socket 对象
		 * @param key 加密
		 * @param delay (单位毫秒) 默认为 0 连接失败后不进行自动重连，如果大于0则按延时毫秒自动重新连接，
		 * 
		 */		
		public function Client(key:String ,delay:Number=0 ,socket:Socket=null)
		{
			_key = key;
			
			_timer = new Timer(delay);
			_timer.addEventListener(TimerEvent.TIMER ,timerHandler);
			
			_socket = socket==null?new Socket():socket;
			_remoteAddress = _socket.remoteAddress;
			_remotePort = _socket.remotePort;
			
			_socket.addEventListener(IOErrorEvent.IO_ERROR ,ioErrorHandler);
			_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR ,securityErrorHandler);
			_socket.addEventListener(Event.CLOSE ,closeHandler);
			_socket.addEventListener(Event.CONNECT ,connectHandler);
			_socket.addEventListener(ProgressEvent.SOCKET_DATA ,socketDataHandler);
		}
		
		
		////////////////////////////////////////////////////////////////////
		//
		//  get
		//
		///////////////////////////////////////////////////////////////////
		
		private var _cmd:String;
		private var _data:ByteArray;
		private var _bytesTotal:Number;
		private var _bytesLoaded:Number;
		private var _remoteAddress:String;
		private var _remotePort:int;
		
		
		/** 远程设备的 IP 地址 */
		public function get remoteAddress():String {return _remoteAddress;}
		
		/** 远程设备的端口 */
		public function get remotePort():int {return _remotePort;}
		
		/** 参数 */
		public function get data():ByteArray {return _data;}
		
		/** 命令 */
		public function get cmd():String {return _cmd;}
		
		/** 数据包已加载字节 */
		public function get bytesLoaded():Number {return _bytesLoaded;}
		
		/** 数据包总字节 */
		public function get bytesTotal():Number {return _bytesTotal;}
		
		
		////////////////////////////////////////////////////////////////////
		//
		//  public
		//
		///////////////////////////////////////////////////////////////////
		
		
		/**
		 * 发送数据
		 * @param cmd
		 * @param value
		 * 
		 */		
		public function send(cmd:String ,value:ByteArray=null):void
		{
			if(_socket.connected==true)
			{
				_socket.writeUTF(_key==null?cmd:AES.encrypt(cmd ,_key ,AES.BIT_KEY_192));
				_socket.writeInt(value==null?0:value.length);
				if(value!=null)_socket.writeBytes(value ,0 ,value.length);
				_socket.flush();
			}else{
				dispatchEvent(new ClientEvent(ClientEvent.CONNECT_FAILED ,this));
			}
		}
		
		
		
		/**
		 * 连接服务器
		 * @param serverAddress
		 * @param serverPort
		 * 
		 */		
		public function connect(serverAddress:String ,serverPort:uint):void
		{
			_close = false;
			_serverAddress = serverAddress;
			_serverPort = serverPort;
			timerHandler(null);
		}
		
		/**
		 * 关闭连接
		 * 
		 */		
		public function close():void
		{
			_close = true;
			_timer.stop();
			if(_socket.connected)_socket.close();
		}
		
		
		
		////////////////////////////////////////////////////////////////////
		//
		//  Event
		//
		///////////////////////////////////////////////////////////////////
		
		/** 安全沙箱错误 */
		private function securityErrorHandler(event:SecurityErrorEvent):void {}
		
		/** IO错误 */
		private function ioErrorHandler(event:IOErrorEvent):void 
		{
			_bytesTotal = 0;
			_isHeader = true;
			
			if(_socket.connected)
			{
				dispatchEvent(new ClientEvent(ClientEvent.IO_ERROR ,this));
			}else{
				closeHandler(null);
			}
		}
		
		/** 连接断开 */
		private function closeHandler(event:Event):void 
		{
			dispatchEvent(new ClientEvent(ClientEvent.CONNECT_FAILED ,this));
			if(_close==false)_timer.start();
		}
		
		/** 重新连接计时器处理 */
		private function timerHandler(event:TimerEvent):void
		{
			_timer.stop();
			//如果构建函数未设置则不自动连接
			if(_timer.delay>0)_socket.connect(_serverAddress ,_serverPort);
		}
		
		/** 连接成功 */
		private function connectHandler(event:Event):void
		{
			_timer.stop();
			_bytesTotal = 0;
			_isHeader = true;
			dispatchEvent(new ClientEvent(ClientEvent.CONNECT_SUCCEED ,this));
		}
		
		/** 数据处理 */
		private function socketDataHandler(event:ProgressEvent):void 
		{
			try{
				//数据包头处理
				if(_isHeader && _socket.bytesAvailable>4)
				{
					_cmd = _key==null?_socket.readUTF():AES.decrypt(_socket.readUTF() ,_key ,AES.BIT_KEY_192);
					_bytesTotal = _socket.readInt();
					_isHeader = false;
				}
				
				//数据包加载进度
				if(!_isHeader)
				{
					_bytesLoaded = _socket.bytesAvailable;
					dispatchEvent(new ClientEvent(ClientEvent.PROGRESS ,this));
				}
				
				//数据包加载完成
				if(!_isHeader && _socket.bytesAvailable>=_bytesTotal)
				{
					if(_data!=null)
					{
						_data.clear();
						_data = null;
					}
					
					if(_bytesTotal>0)
					{
						_data = new ByteArray();
						_socket.readBytes(_data ,0 ,_socket.bytesAvailable);
					}
					
					_isHeader = true;
					dispatchEvent(new ClientEvent(ClientEvent.RECEIVE ,this));
				}
			}catch(e:Error){
				ioErrorHandler(null);
			}
		}
	}
}